#include "http_request.h"

#include <QDebug>
#include <cstring>

#define CR '\r'
#define LF '\n'

namespace {

// 字符串的buf，只存储对应的指针，不存储实际的内容
struct MutableBuffer
{
    char *begin = nullptr;//字符串开始位置
    char *end = nullptr;//字符串结束位置

    operator QByteArray() const
    {
        return QByteArray::fromStdString(std::string(begin, end));
    }
};

}

HttpRequest::HttpRequest()
    : m_nextPos(0)
    , m_bodyLength(0)
    , m_curScanPos(0)
    , m_decodeState(HttpRequestDecodeState::kStart)
{

}

/**
 * @brief HttpRequest::tryDecode 解析HTTP报文
 * @param httpMessage http报文
 */
void HttpRequest::tryDecode(const QByteArray &httpMessage)
{
    // 如果上次的状态是kBody，因为HTTP消息不完整导致的解析终止，
    // 则这里从上次decode位置的下一位开始,避免重复解析，优化速度,
    // 对于kBody之前的状态，因为数据量不大，这里的处理是直接从头开始解析
    if (m_decodeState == HttpRequestDecodeState::kBody) {
        m_nextPos = m_curScanPos + 1;
    } else {
        reset();
    }

    parseInternal(httpMessage.data(), static_cast<size_t>(httpMessage.length()));
}

/**
 * @brief HttpRequest::reset 重置状态
 */
void HttpRequest::reset()
{
    m_requestParams.clear();
    m_headers.clear();
    m_body.clear();
    m_nextPos = 0;
    m_bodyLength = 0;
    m_curScanPos = 0;
    m_decodeState = HttpRequestDecodeState::kStart;
}

/**
 * @brief HttpRequest::parseInternal 解析HTTP报文数据
 * @param strBuf buffer的指针
 * @param size buffer的长度
 */
void HttpRequest::parseInternal(const char *strBuf, size_t size)
{
    MutableBuffer method;
    MutableBuffer url;

    MutableBuffer requestParamKey;
    MutableBuffer requestParamValue;

    MutableBuffer protocol;
    MutableBuffer version;

    MutableBuffer headerKey;
    MutableBuffer headerValue;

    char *pStart = const_cast<char *>(strBuf + m_nextPos);

    while (m_nextPos < size
           && m_decodeState != HttpRequestDecodeState::kInvalid
           && m_decodeState != HttpRequestDecodeState::kInvalidMethod
           && m_decodeState != HttpRequestDecodeState::kInvalidUri
           && m_decodeState != HttpRequestDecodeState::kInvalidVersion
           && m_decodeState != HttpRequestDecodeState::kInvalidHeader
           && m_decodeState != HttpRequestDecodeState::kComplete) {

        const char curChar = *pStart; //当前的字符
        char *pCurChar = pStart++; // 当前字符的指针
        m_curScanPos = m_nextPos++; //当前字符的position

        switch (m_decodeState) {
        case HttpRequestDecodeState::kStart: {
            //空白字符,换行,回车
            //这里不能使用isspace函数用于判断空白字符,ASCII 编码下，isblank就是 ' ' 和 '\t'
            if (curChar == CR || curChar == LF || isblank(curChar)) {
                //do nothing
            } else if (isupper(curChar)) { //判断是不是大写字符，不是大写字符就是无效的
                method.begin = pCurChar; //方法的起始点
                m_decodeState = HttpRequestDecodeState::kMethod; //如果遇到第一个字符，开始解析方法
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalid;
            }
            break;
        }
        case HttpRequestDecodeState::kMethod: {
            //方法需要大写字母，大写字母就继续
            if (isupper(curChar)) {
                //do nothing
            } else if (isblank(curChar)) { //空格，说明方法解析结束，下一步开始解析URI
                method.end = pCurChar; //方法解析结束
                m_method = method;
                m_decodeState = HttpRequestDecodeState::kBeforeUrl;
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalidMethod; //其他情况是无效的请求方法
            }
            break;
        }
        case HttpRequestDecodeState::kBeforeUrl: {
            //请求连接前的处理，需要'/'开头
            if (curChar == '/') {
                url.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kInUrl; //下一步就是开始处理连接
            } else if (isblank(curChar)) {
                //do nothing
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalid; //无效的
            }
            break;
        }
        case HttpRequestDecodeState::kInUrl: {
            //开始处理请求路径的字符串
            if (curChar == '?') { //转为处理请求的key值
                url.end = pCurChar;
                m_url = url;
                m_decodeState = HttpRequestDecodeState::kBeforeUriParamKey;
            } else if (isblank(curChar)) { //遇到空格，请求路径解析完成，开始解析协议
                url.end = pCurChar;
                m_url = url;
                m_decodeState = HttpRequestDecodeState::kBeforeProtocol;
            } else {
                //do nothing
            }
            break;
        }
        case HttpRequestDecodeState::kBeforeUriParamKey: {
            if (isblank(curChar) || curChar == LF || curChar == CR) {
                m_decodeState = HttpRequestDecodeState::kInvalidUri;
            } else {
                requestParamKey.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kUriParamKey;
            }
            break;
        }
        case HttpRequestDecodeState::kUriParamKey: {
            if (curChar == '=') {
                requestParamKey.end = pCurChar;
                m_decodeState = HttpRequestDecodeState::kBeforeUriParamValue; //开始解析参数值
            } else if (isblank(curChar)) {
                m_decodeState = HttpRequestDecodeState::kInvalidUri; //无效的请求参数
            } else {
                //do nothing
            }
            break;
        }
        case HttpRequestDecodeState::kBeforeUriParamValue: {
            if (isblank(curChar) || curChar == LF || curChar == CR) {
                m_decodeState = HttpRequestDecodeState::kInvalidUri;
            } else {
                requestParamValue.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kUriParamValue;
            }
            break;
        }
        case HttpRequestDecodeState::kUriParamValue: {
            if (curChar == '&') {
                requestParamValue.end = pCurChar;
                //收获一个请求参数
                m_requestParams.insert(requestParamKey, requestParamValue);

                m_decodeState = HttpRequestDecodeState::kBeforeUriParamKey;
            } else if (isblank(curChar)) {
                requestParamValue.end = pCurChar;
                //遇到空白字符，URL结束,收获一个请求参数
                m_requestParams.insert(requestParamKey, requestParamValue);
                m_decodeState = HttpRequestDecodeState::kBeforeProtocol;
            } else {
                //do nothing
            }
            break;
        }
        case HttpRequestDecodeState::kBeforeProtocol: {
            if (isblank(curChar)) {
                //do nothing
            } else {
                protocol.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kProtocol;
            }
            break;
        }
        case HttpRequestDecodeState::kProtocol: {
            //解析请求协议
            if (curChar == '/') {
                protocol.end = pCurChar;
                m_protocol = protocol;
                m_decodeState = HttpRequestDecodeState::kBeforeVersion;
            } else {
                //do nothing
            }
            break;
        }
        case HttpRequestDecodeState::kBeforeVersion: {
            if (isdigit(curChar)) {
                version.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kVersion;
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalidVersion;
            }
            break;
        }
        case HttpRequestDecodeState::kVersion: {
            //协议解析，如果不是数字或者. 就不对
            if (curChar == CR) {
                version.end = pCurChar;
                m_version = version;
                m_decodeState = HttpRequestDecodeState::kWhenCR;
            } else if (curChar == '.') {
                //遇到版本分割
                m_decodeState = HttpRequestDecodeState::kVersionSplit;
            } else if (isdigit(curChar)) {
                //do nothing
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalidVersion; //不能不是数字
            }
            break;
        }
        case HttpRequestDecodeState::kVersionSplit: {
                //遇到版本分割符，字符必须是数字，其他情况都是错误
            if (isdigit(curChar)) {
                m_decodeState = HttpRequestDecodeState::kVersion;
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalidVersion;
            }
            break;
        }
        case HttpRequestDecodeState::kHeaderKey: {
            //冒号前后可能有空白字符
            if (isblank(curChar)) {
                headerKey.end = pCurChar;
                m_decodeState = HttpRequestDecodeState::kHeaderBeforeColon; //冒号之前的状态
            } else if (curChar == ':') {
                headerKey.end = pCurChar;
                m_decodeState = HttpRequestDecodeState::kHeaderAfterColon; //冒号之后的状态
            } else {
                //do nothing
            }
            break;
        }
        case HttpRequestDecodeState::kHeaderBeforeColon: {
            if (isblank(curChar)) {
                //do nothing
            } else if (curChar == ':') {
                m_decodeState = HttpRequestDecodeState::kHeaderAfterColon;
            } else {
                //冒号之前的状态不能是空白字符之外的其他字符
                m_decodeState = HttpRequestDecodeState::kInvalidHeader;
            }
            break;
        }
        case HttpRequestDecodeState::kHeaderAfterColon: {
            if (isblank(curChar)) { //值之前遇到空白字符都是正常的
                //do nothing
            } else {
                headerValue.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kHeaderValue; //开始处理值
            }
            break;
        }
        case HttpRequestDecodeState::kHeaderValue: {
            if (curChar == CR) {
                headerValue.end = pCurChar;
                m_headers.insert(headerKey, headerValue);
                m_decodeState = HttpRequestDecodeState::kWhenCR;
            }
            break;
        }
        case HttpRequestDecodeState::kWhenCR: {
            if (curChar == LF) {
                //如果是回车，可换成下一个
                m_decodeState = HttpRequestDecodeState::kCRLF;
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalid;
            }
            break;
        }
        case HttpRequestDecodeState::kCRLF: {
            if (curChar == CR) {
                //如果在CR_LF状态之后还有CR，那么可能处于结束的状态了
                m_decodeState = HttpRequestDecodeState::kCRLFCR;
            } else if (isblank(curChar)) {
                m_decodeState = HttpRequestDecodeState::kInvalid;
            } else {
                //如果不是，那么就可能又是一个请求头了，那就开始解析请求头
                headerKey.begin = pCurChar;
                m_decodeState = HttpRequestDecodeState::kHeaderKey;
            }
            break;
        }
        case HttpRequestDecodeState::kCRLFCR: {
            if (curChar == LF) {
                //如果是\r接着\n, 那么判断是不是需要解析请求体
                if (m_headers.count("Content-Length") > 0) {
                    long int content_length = atol(m_headers["Content-Length"].data());
                    if (content_length < 0) {
                        m_decodeState = HttpRequestDecodeState::kInvalidHeader;
                        break;
                    }
                    m_bodyLength = static_cast<size_t>(content_length);
                    if (m_bodyLength > 0) {
                        m_decodeState = HttpRequestDecodeState::kBody; //解析请求体
                    } else {
                        m_decodeState = HttpRequestDecodeState::kComplete; //完成了
                    }
                } else { //没有Content-Length头部的情况
                    if (m_curScanPos + 1 < size) {
                        m_bodyLength = size - m_curScanPos;
                        m_decodeState = HttpRequestDecodeState::kBody; //解析请求体
                    } else {
                        m_decodeState = HttpRequestDecodeState::kComplete;
                    }
                }
            } else {
                m_decodeState = HttpRequestDecodeState::kInvalidHeader;
            }
            break;
        }
        case HttpRequestDecodeState::kBody: {
            m_body.append(pCurChar, 1);
            if (static_cast<size_t>(m_body.length()) < m_bodyLength) {
                break;
            }
            //解析请求体
            m_decodeState = HttpRequestDecodeState::kComplete;
            break;
        }
        default:
            break;
        }
    }
}

/**
 * @brief HttpRequest::keepAlive 判断HTTP请求报文中是否设置可keep-alive
 * @return true 设置了keep-alive false 没有设置
 */
bool HttpRequest::keepAlive() const
{
    if (m_headers.find("Connection") == m_headers.end()) {
        return false;
    }

    return strcasecmp(m_headers["Connection"].data(), "keep-alive") == 0;
}

/**
 * @brief HttpRequest::getHeader 获取HTTP头部字段的值
 * @param key 头部字段
 * @return 返回头部字段的值
 */
QByteArray HttpRequest::getHeader(const QByteArray &key) const
{
    auto itr = m_headers.find(key);
    if (itr == m_headers.end()) {
        return QByteArray();
    }

    return itr.value();
}

/**
 * @brief HttpRequest::getProcessedValidMessageLength  获取已经处理的有效的HTTP消息长度
 * @return 返回有效的HTTP消息长度
 */
size_t HttpRequest::getProcessedValidMessageLength() const
{
    if (m_decodeState == HttpRequestDecodeState::kInvalid
            || m_decodeState == HttpRequestDecodeState::kInvalidMethod
            || m_decodeState == HttpRequestDecodeState::kInvalidUri
            || m_decodeState == HttpRequestDecodeState::kInvalidVersion
            || m_decodeState == HttpRequestDecodeState::kInvalidHeader) {
        if (m_curScanPos == 0) { //当前位置为0的时候状态非法
            return 0;
        } else {
            return m_curScanPos;
        }
    }

    return m_curScanPos + 1;
}

